import { Subject, Subscription } from "rxjs";

import { _decorator } from 'cc';
const { ccclass, property } = _decorator;

export enum RxSetOp {
    init,
    add,
    clear,
    delete,
    again,
}

@ccclass
export class ReactiveSet<T> {

    static Create<T>(): ReactiveSet<T> {
        return new ReactiveSet<T>().init();
    }

    private set: Set<T>;

    _subject: Subject<{ op: RxSetOp, v?: T }> = null;

    init(): ReactiveSet<T> {
        this.set = new Set<T>();
        this._subject = new Subject<{ op: RxSetOp, v?: T }>();
        return this;
    }

    get value(): Set<T> {
        return this.set;
    }

    set value(value: Set<T>) {
        this.set = value;
        this._subject.next({ op: RxSetOp.init });
    }

    add(item: T) {
        this.set.add(item);
        this._subject.next({ op: RxSetOp.add, v: item });
    }

    clear() {
        this.set.clear();
        this._subject.next({ op: RxSetOp.clear });
    }

    delete(item: T) {
        this.set.delete(item);
        this._subject.next({ op: RxSetOp.delete, v: item });
    }

    forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any) {
        this.set.forEach(callbackfn);
    }

    has(item: T) {
        return this.set.has(item);
    }

    get size() {
        return this.set.size;
    }

    subscribe(next: (value: { op: RxSetOp; v?: T; }) => void): Subscription {
        const _sub = this._subject.subscribe(next);
        this._subject.next({ op: RxSetOp.again });
        return _sub;
    }

    again() {
        this._subject.next({ op: RxSetOp.again });
    }
}